# -*- coding: utf-8 -*-
import collections
import os

import pyglet
from pyglet.gl import *

from attrdict import attrdict
from constants import SHORT_NAME


current_music = None


# Having this here is not logical, but meh.
class EndOfGame(Exception):
    pass


def setup_user_data():
    directory = pyglet.resource.get_settings_path(SHORT_NAME)
    if not os.path.exists(directory):
        os.makedirs(directory)
    if not os.path.exists(os.path.join(directory, "progress")):
        filename = os.path.join(directory, "progress")
        open(filename, "wt").write("0")

def get_current_level_number():
    directory = pyglet.resource.get_settings_path(SHORT_NAME)
    filename = os.path.join(directory, "progress")
    if not os.path.exists(filename) :
        setup_user_data()

    progress = open(filename, "rt").read()

    try:
        return int(progress)
    except ValueError:
        utils.error("Malformed progress file!" + progress)
        return 0


def get_current_level():
    level_num = get_current_level_number()

    if level_num >= len(all_levels()):
        raise EndOfGame()

    return all_levels()[level_num]


def set_level(n):
    directory = pyglet.resource.get_settings_path(SHORT_NAME)
    if not os.path.exists(directory):
        setup_user_data()

    filename = os.path.join(directory, "progress")
    open(filename, "wt").write(str(n))


def store_level_success():
    directory = pyglet.resource.get_settings_path(SHORT_NAME)
    if not os.path.exists(directory):
        setup_user_data()

    level_num = get_current_level_number() + 1

    set_level(level_num)

    if level_num > len(all_levels()):
        raise EndOfGame()


def all_levels():
    directory = os.path.join(pyglet.resource.get_script_home(),
                             "data", "levels", "peano")
    with open(directory, "rt") as f:
        return [l.strip() for l in f.read().split("\n") if l.strip() and not l.strip().startswith("#")]


def load_level(mode, filename):
    scope = attrdict()
    scope.__dict__ = scope

    from lib.wall import Wall
    from lib.player import Player
    from lib.goal import Goal
    from lib.box import Box
    from lib.relation import Relation
    from lib.portal import Portal
    from lib.electricals import Button, Lever, Door, Contraption
    from lib.note import Note
    from lib.idlist import L

    import math

    l = locals()

    def with_mode(s):
        return lambda *opt, **kwargs: l[s](mode, *opt, **kwargs)

    for s in ["Wall", "Player",
              "Goal", "Box",
              "Portal", "Button",
              "Door", "Lever",
              "Note",
              "Contraption"]:
        scope[s] = with_mode(s)
    for s in ["math", "Relation", "L"]:
        scope[s] = l[s]
    scope["pi"] = math.pi
    scope["π"] = math.pi

    execfile(os.path.join(pyglet.resource.get_script_home(),
                          "data", "levels", filename),
             scope)
    scope.name = filename
    return scope


def play_music(filename, player):
    global current_music

    if not filename == current_music:
        source = pyglet.resource.media(filename)
        current_music = filename

        player.next()
        player.queue(source)
        player.play()


def texture_set_mag_filter_nearest(texture):
    glBindTexture(texture.target, texture.id)
    glTexParameteri(texture.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glBindTexture(texture.target, 0)


def image(filename, (x, y), flip_x=False, flip_y=False, antialiasing=False):
    """Load an image and anchor it.
    (x, y) is the ratios of the width and height respectively
    on which to put the anchor, counted from the lower left
    corner."""

    # Using resource.image loads the image into a shared texture that
    # is not aligned with our sub-pixel coordinates, giving a black
    # border.
    # (http://groups.google.com/group/pyglet-users/browse_thread/thread/f8ff65d40321dba6?pli=1)
    fullname = os.path.join(pyglet.resource.location(filename).path, filename)
    image = pyglet.image.load(fullname)

    # TODO: Using this breaks the image anchoring. Look into it!
    #if not antialiasing:
    #    texture_set_mag_filter_nearest(image.get_texture())

    image = image.get_texture().get_transform(flip_x=flip_x, flip_y=flip_y)

    # Not converting to an integer gives a strange ctypes type error
    # that was really hard to decode.
    image.anchor_x = int(image.width * x)
    image.anchor_y = int(image.height * y)

    return image


def image_grid(filename, (x, y), (rows, cols), flip_x=False, flip_y=False, antialiasing=False):
    """Load an image, divides into a grid and anchor each respective
    image.  (x, y) is the ratios of the width and height respectively
    on which to put the anchor, counted from the lower left corner."""

    # Using resource.image loads the image into a shared texture that
    # is not aligned with our sub-pixel coordinates, giving a black
    # border.
    # (http://groups.google.com/group/pyglet-users/browse_thread/thread/f8ff65d40321dba6?pli=1)
    fullname = os.path.join(pyglet.resource.location(filename).path, filename)
    image = pyglet.image.load(fullname)

    image = image.get_texture().get_transform(flip_x=flip_x, flip_y=flip_y)

    grid = pyglet.image.ImageGrid(image, rows, cols)

    if not antialiasing:
        texture_set_mag_filter_nearest(grid.get_texture())

    for img in grid:
        # Not converting to an integer gives a strange ctypes type error
        # that was really hard to decode.
        img.anchor_x = int(img.width * x)
        img.anchor_y = int(img.height * y)

    return grid
